package br.odb.utils.math;

import br.odb.utils.math.Matrix;



/**
 * 
 * @author Daniel "Monty" Monteiro
 *
 */

public class Vec3  {

	/**
	 * 
	 */
	private float x;
	/**
	 * 
	 */
	private float y;
	/**
	 * 
	 */
	private float z;
	/**
	 * 
	 */
	private int index;
	/**
	 * 
	 */
	private int space;
	/**
	 * 
	 */
	public Vec3() {
		this( 0, 0, 0 );
		setIndex(0);
		setSpace(0);
	}
	
	
	/**
	 * 
	 * @param v
	 */
	public Vec3( Vec3 v ) {
		setX(v.getX());
		setY(v.getY());
		setZ(v.getZ());
		setIndex(v.getIndex());
		setSpace(v.getSpace());
	}
	
	
	/**
	 * 
	 * @param x2
	 * @param y2
	 * @param z2
	 */
	public Vec3(float x2, float y2, float z2) {
		setX(x2);
		setY(y2);
		setZ(z2);
		setIndex(-1);
		setSpace(0);
	}

	public String toString() {
		String toReturn = "";
		toReturn += "Vec3[";		
		toReturn += getIndex();
		toReturn += "]";
		toReturn += "=";
		toReturn += "( ";
		toReturn += getX();
		toReturn += ", ";
		toReturn += getY();
		toReturn += ", ";
		toReturn += getZ();
		toReturn += " ):";
		toReturn += getSpace();
		return toReturn;
	}
	
	/**
	 * 	
	 */
	public int hashCode(){	
		return toString().hashCode();
	}
	
	
	/**
	 * 
	 */
	public boolean equals(Object that) {
		if (this == that)
			return true;
		if (!(that instanceof Vec3))
			return false;
		Vec3 v = (Vec3) that;
		return v.getX() == getX() && v.getY() == getY() && v.getZ() == getZ();
	}

	
	public float length() {
		return (float) Math.sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
	}
	
	public void normalize() {

		float oneOverLen = 1 / length();
		scale( oneOverLen );
	}


	public void scale( float real ) {
		
		setX( getX() * real );
		setY( getY() * real );
		setZ( getZ() * real );		
	}

	public void transform( Matrix matrix ) {
		
		Vec3 copyThis = new Vec3( this );
		//eu sou uma coluna
		setX(( copyThis.getX() * matrix.values[ 0 ][ 0 ] ) + ( copyThis.getY() * matrix.values[ 0 ][ 1 ] ) + ( copyThis.getZ() * matrix.values[ 0 ][ 2 ] ));  
		setY(( copyThis.getX() * matrix.values[ 1 ][ 0 ] ) + ( copyThis.getY() * matrix.values[ 1 ][ 1 ] ) + ( copyThis.getZ() * matrix.values[ 1 ][ 2 ] ));
		setZ(( copyThis.getX() * matrix.values[ 2 ][ 0 ] ) + ( copyThis.getY() * matrix.values[ 2 ][ 1 ] ) + ( copyThis.getZ() * matrix.values[ 2 ][ 2 ] ));
		
		//eu sou uma linha
//		x = ( copyThis.x * matrix.values[ 0 ][ 0 ] ) + ( copyThis.y * matrix.values[ 1 ][ 0 ] ) + ( copyThis.z * matrix.values[ 2 ][ 0 ] );  
//		y = ( copyThis.x * matrix.values[ 0 ][ 1 ] ) + ( copyThis.y * matrix.values[ 1 ][ 1 ] ) + ( copyThis.z * matrix.values[ 2 ][ 1 ] );
//		z = ( copyThis.x * matrix.values[ 0 ][ 2 ] ) + ( copyThis.y * matrix.values[ 1 ][ 2 ] ) + ( copyThis.z * matrix.values[ 2 ][ 2 ] );		
		
	}
	

	public Vec3 sub(Vec3 place) {
		
		Vec3 toReturn = new Vec3();
		toReturn.setX( getX() - place.getX());
		toReturn.setY( getY() - place.getY());
		toReturn.setZ( getZ() - place.getZ());
		
		return toReturn;
	}

	public Vec3 add(Vec3 delta) {
		
		Vec3 toReturn = new Vec3();
		
		toReturn.setX(getX() + delta.getX());
		toReturn.setY(getY() + delta.getY());
		toReturn.setZ(getZ() + delta.getZ());
		
		return toReturn;
	}

	public void copy(Vec3 place) {
		setX(place.getX());
		setY(place.getY());
		setZ(place.getZ());		
		setSpace(place.getSpace());
		setIndex(place.getIndex());
	}

	public void set(float _x, float _y, float _z ) {
		setX(_x);
		setY(_y);
		setZ(_z); 
	}
	

	public Vec3 makeCopy() {
		return new Vec3( this );
	}


	/**
	 * @return the x
	 */
	public float getX() {
		return x;
	}


	/**
	 * @param x the x to set
	 */
	public void setX(float x) {
		this.x = x;
	}


	/**
	 * @return the y
	 */
	public float getY() {
		return y;
	}


	/**
	 * @param y the y to set
	 */
	public void setY(float y) {
		this.y = y;
	}


	/**
	 * @return the z
	 */
	public float getZ() {
		return z;
	}


	/**
	 * @param z the z to set
	 */
	public void setZ(float z) {
		this.z = z;
	}


	/**
	 * @return the index
	 */
	public int getIndex() {
		return index;
	}


	/**
	 * @param index the index to set
	 */
	public void setIndex(int index) {
		this.index = index;
	}


	/**
	 * @return the space
	 */
	public int getSpace() {
		return space;
	}


	/**
	 * @param space the space to set
	 */
	public void setSpace(int space) {
		this.space = space;
	}


	public void set( Vec3 v ) {
		set( v.getX(), v.getY(), v.getZ() );		
	}


	public Vec3 normalized() {

		Vec3 length1 = new Vec3( this );
		length1.normalize();
		return length1;
	}


	public void addTo( Vec3 v ) {
		
		x += v.getX();
		y += v.getY();
		z += v.getZ();		
	}


	public void addTo(float x2, float y2, float z2) {

		x += x2;
		y += y2;
		z += z2;
	}
}
